package com.mentalhealthplatform.global.rbac.service.entity;

import com.mentalhealthplatform.exception.permssion.PermissionNotFoundException;
import com.mentalhealthplatform.global.rbac.controller.EndpointController;
import com.mentalhealthplatform.global.rbac.dto.normal.MenuDTO;
import com.mentalhealthplatform.global.rbac.dto.normal.BaseUserDTO;
import com.mentalhealthplatform.global.rbac.dto.request.AuthRequest;
import com.mentalhealthplatform.global.rbac.dto.request.UserRegistrationRequest;
import com.mentalhealthplatform.global.rbac.dto.response.AuthResponse;
import com.mentalhealthplatform.exception.user.UserAlreadyExistsException;
import com.mentalhealthplatform.exception.user.UserNotFoundException;
import com.mentalhealthplatform.global.rbac.model.CustomUserDetails;
import com.mentalhealthplatform.global.rbac.model.Menu;
import com.mentalhealthplatform.global.rbac.model.Role;
import com.mentalhealthplatform.global.rbac.model.User;
import com.mentalhealthplatform.global.rbac.repository.PermissionRepository;
import com.mentalhealthplatform.global.rbac.repository.RoleRepository;
import com.mentalhealthplatform.global.rbac.repository.BaseUserRepository;
import com.mentalhealthplatform.global.rbac.jwt.JwtUtils;
import com.mentalhealthplatform.global.rbac.service.UserDetailsServiceImpl;
import com.mentalhealthplatform.global.rbac.service.relation.RoleMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class BaseUserService {

    @Autowired
    private BaseUserRepository baseUserRepository;

    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private PermissionRepository permissionRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RoleMenuService roleMenuService;

    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private EndpointController endpointController;

    /**
     * 注册新用户，使用加密后的密码，并为用户分配默认角色。
     *
     * @param registrationRequest 要注册的用户对象
     * @return 保存后的用户对象
     */
    public User registerUser(UserRegistrationRequest registrationRequest) {
        // 检查用户名和电子邮件是否已存在
        if (baseUserRepository.existsByUsername(registrationRequest.getUsername())) {
            throw new UserAlreadyExistsException("用户名已存在。");
        }

        // 创建新用户并加密密码
        User user = new User();
        user.setUsername(registrationRequest.getUsername());
        user.setPassword(passwordEncoder.encode(registrationRequest.getPassword()));
        // 为新用户分配默认角色，如 "ROLE_USER"
        Optional<Role> defaultRole = roleRepository.findByIdentifier("ROLE_USER");
        user.setRoles(new HashSet<>());
        defaultRole.ifPresent(role -> user.getRoles().add(role));
        return baseUserRepository.save(user);
    }

    /**
     * 用户身份验证，根据用户名和密码进行验证，并生成 JWT 令牌。
     *
     * @param authRequest 包含用户名和密码的认证请求对象
     * @param checkRole 需要验证用户是否符合身份
     * @return 生成的 JWT 令牌和用户详细信息
     * @throws AuthenticationException 如果用户名或密码错误，抛出身份验证异常
     */
    public AuthResponse authenticate(AuthRequest authRequest,String checkRole) throws AuthenticationException {
        try {
            // 使用 AuthenticationManager 验证用户名和密码
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())
            );

            // 如果验证成功，将 Authentication 对象存入 SecurityContext
            SecurityContextHolder.getContext().setAuthentication(authentication);

            // 获取用户详细信息，明确类型转换为 CustomUserDetails
            CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();


            if (!userDetails.hasRole(checkRole)) {
                throw new PermissionNotFoundException("认证未通过");
            }

            // 生成 JWT 令牌（包括用户名、角色和权限等信息）
            String token = jwtUtils.generateToken(userDetails);

            // 获取令牌的过期时间（根据 jwtUtils 实现）
            Date expirationDate = jwtUtils.extractExpiration(token);

            // 获取用户菜单层次结构
            Set<MenuDTO> userMenus = getUserMenuHierarchy(userDetails.getId());

            // 构建 AuthResponse 对象
            AuthResponse authResponse = new AuthResponse();
            authResponse.setToken(token);
            authResponse.setUsername(userDetails.getUsername());
            authResponse.setExpiration(expirationDate);
            authResponse.setPermissions(userDetails.getPermissions());
            authResponse.setRoles(userDetails.getRoles());
            // 设置用户的菜单层次结构
            authResponse.setMenus(userMenus);

            return authResponse;
        } catch (AuthenticationException ex) {
            // 如果认证失败，抛出 AuthenticationException 供控制器捕获处理
            throw ex;
        }
    }

    /**
     * 用户身份验证，根据用户名和密码进行验证，并生成 JWT 令牌。
     *
     * @param authRequest 包含用户名和密码的认证请求对象
     * @return 生成的 JWT 令牌和用户详细信息
     * @throws AuthenticationException 如果用户名或密码错误，抛出身份验证异常
     */
    public AuthResponse authenticate(AuthRequest authRequest) throws AuthenticationException {
        try {
            // 使用 AuthenticationManager 验证用户名和密码
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())
            );

            // 如果验证成功，将 Authentication 对象存入 SecurityContext
            SecurityContextHolder.getContext().setAuthentication(authentication);

            // 获取用户详细信息，明确类型转换为 CustomUserDetails
            CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();


            // 生成 JWT 令牌（包括用户名、角色和权限等信息）
            String token = jwtUtils.generateToken(userDetails);

            // 获取令牌的过期时间（根据 jwtUtils 实现）
            Date expirationDate = jwtUtils.extractExpiration(token);

            // 获取用户菜单层次结构
            Set<MenuDTO> userMenus = getUserMenuHierarchy(userDetails.getId());

            // 构建 AuthResponse 对象
            AuthResponse authResponse = new AuthResponse();
            authResponse.setToken(token);
            authResponse.setUsername(userDetails.getUsername());
            authResponse.setExpiration(expirationDate);
            authResponse.setPermissions(userDetails.getPermissions());
            authResponse.setRoles(userDetails.getRoles());
            authResponse.setMenus(userMenus); // 设置用户的菜单层次结构

            return authResponse;
        } catch (AuthenticationException ex) {
            // 如果认证失败，抛出 AuthenticationException 供控制器捕获处理
            throw ex;
        }
    }


    /**
     * 获取指定用户的所有权限。
     *
     * @param user 用户对象
     * @return 用户拥有的权限集合
     */
    public Set<String> getUserPermissions(User user) {
        Set<String> permissions = new HashSet<>();
        for (Role role : user.getRoles()) {
            role.getPermissions().forEach(permission -> permissions.add(permission.getIdentifier()));
        }
        return permissions;
    }

    /**
     * 检查用户是否拥有指定的权限。
     *
     * @param user 用户对象
     * @param permissionName 权限名称
     * @return 如果用户拥有指定权限，则返回 true；否则返回 false
     */
    public boolean hasPermission(User user, String permissionName) {
        return user.getRoles().stream()
                .flatMap(role -> role.getPermissions().stream())
                .anyMatch(permission -> permission.getIdentifier().equals(permissionName));
    }


    /**
     * 根据用户名获取用户。
     *
     * @param username 用户名
     * @return 包含用户对象的 Optional
     */
    public Optional<User> findByUsername(String username) {
        return baseUserRepository.findByUsername(username);
    }

    /**
     * 根据 ID 查找用户
     *
     * @param userId 用户的唯一标识符（ID）
     * @return 用户对象
     * @throws RuntimeException 如果未找到用户，抛出运行时异常
     */
    public User findById(UUID userId) {
        return baseUserRepository.findById(userId)
                .orElseThrow(() -> new RuntimeException("User not found"));
    }


    //////////////////////////
    ///
    /// 复杂方法
    ///
    /////////////////////////
    // 获取用户所有角色关联的菜单，并返回按层级结构组织的 MenuDTO
    public Set<MenuDTO> getUserMenuHierarchy(UUID userId) {
        // 获取用户实体
        User user = baseUserRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));

        Set<Menu> allMenus = new HashSet<>();
        // 遍历用户所有角色，获取角色关联的菜单
        for (Role role : user.getRoles()) {
            if (!role.isEnabled()){
                // 角色被禁用跳过
                continue;
            }
            allMenus.addAll(role.getMenus());
        }

        // 构建菜单层级
        Set<MenuDTO> topLevelMenus = buildMenuHierarchy(allMenus).stream()
                .map(MenuDTO::new)
                .collect(Collectors.toSet());

        return topLevelMenus;
    }

    // 构建菜单的层级结构
    private Set<Menu> buildMenuHierarchy(Set<Menu> menus) {
        Set<Menu> topLevelMenus = menus.stream()
                .filter(menu -> menu.getParentMenu() == null)
                .collect(Collectors.toSet());

        // 给每个菜单添加子菜单
        for (Menu menu : topLevelMenus) {
            buildChildren(menu, menus);
        }

        return topLevelMenus;
    }

    // 递归构建子菜单
    private void buildChildren(Menu parentMenu, Set<Menu> allMenus) {
        // 获取所有子菜单
        Set<Menu> children = allMenus.stream()
                .filter(menu -> parentMenu.equals(menu.getParentMenu())) // 找到所有子菜单
                .collect(Collectors.toSet());

        parentMenu.setChildMenus(children); // 设置子菜单

        // 递归处理子菜单的子菜单
        for (Menu childMenu : children) {
            buildChildren(childMenu, allMenus); // 递归调用，处理每个子菜单的层级结构
        }
    }

///////////////////////////////////////////////////////////////
public Optional<User> getUserById(UUID id) {
    return baseUserRepository.findById(id)
            .or(() -> {
                throw new UserNotFoundException("User with ID " + id + " not found");
            });
}

    public User createUserIfNotFound(String username, String password) {
        // 尝试查找是否已存在用户
        Optional<User> existingUser = baseUserRepository.findByUsername(username);

        // 如果用户已存在，直接返回
        if (existingUser.isPresent()) {
            return existingUser.get();
        }

        // 如果用户不存在，创建并保存新用户
        User user = new User();
        user.setUsername(username);
        // 使用 passwordEncoder 加密密码
        user.setPassword(passwordEncoder.encode(password));

        return baseUserRepository.save(user);
    }

    // 更新用户信息
    public void updateUser(UUID id, BaseUserDTO baseUserDTO) {
        // 检查用户名是否被其他用户占用
        Optional<User> userWithSameUsername = baseUserRepository.findByUsernameAndIdNot(baseUserDTO.getUsername(), id);
        if (userWithSameUsername.isPresent()) {
            throw new UserAlreadyExistsException("用户名已存在");
        }

        // 从数据库中查找用户
        User user = baseUserRepository.findById(id).orElseThrow(() -> new UserNotFoundException("用户不存在"));

        // 更新用户信息
        user.setUsername(baseUserDTO.getUsername());
        user.setStatus(baseUserDTO.isStatus());

        // 保存更新后的用户信息
        baseUserRepository.save(user);
    }

    // 删除用户
    public void deleteUser(UUID id) {
        // 首先检查实体是否存在
        User user = baseUserRepository.findById(id)
                .orElseThrow(() -> new UserNotFoundException("User with ID " + id + " not found"));

        // 执行删除操作
        baseUserRepository.deleteById(id);
    }

    // 切换用户状态
    public void toggleUserStatus(UUID id) {
        User user = baseUserRepository.findById(id).orElseThrow(() -> new UserNotFoundException("User not found"));
        user.toggleStatus();
        baseUserRepository.save(user);
    }

    // 获取所有用户
    public List<User> getAllUsers() {
        return baseUserRepository.findAll();
    }

    // 添加用户
    public User addUser(BaseUserDTO baseUserDTO) {
        // 检查用户是否已存在
        if (baseUserRepository.existsByUsername(baseUserDTO.getUsername())) {
            throw new UserAlreadyExistsException("用户已存在: " + baseUserDTO.getUsername());
        }

        // 将 DTO 转换为实体类
        User user = new User();
        user.setUsername(baseUserDTO.getUsername());
        user.setStatus(baseUserDTO.isStatus());
        user.setPassword(passwordEncoder.encode("123456")); // 设置默认密码并加密

        // 保存用户到数据库
        return baseUserRepository.save(user);
    }

    // 更新用户状态
    public void updateUserStatus(UUID id, Boolean status) {
        // 首先检查实体是否存在
        User user = baseUserRepository.findById(id)
                .orElseThrow(() -> new UserNotFoundException("User with ID " + id + " not found"));

        user.setStatus(status);

        baseUserRepository.save(user);
    }
}
